#include <iostream>
#include <string>

class Product
{
public:
    void makeA(const std::string &part)
    {
        partA = part;
    }

    void makeB(const std::string &part)
    {
        partB = part;
    }

    void makeC(const std::string &part)
    {
        partC = part;
    }

    std::string get()
    {
        return (partA + " " + partB + " " + partC);
    }

private:
    std::string partA;
    std::string partB;
    std::string partC;
};

class Builder
{
public:
    virtual ~Builder() {}

    Product get()
    {
        return product;
    }

    virtual void buildPartA() = 0;
    virtual void buildPartB() = 0;
    virtual void buildPartC() = 0;

protected:
    Product product;
};

class ConcreteBuilderX : public Builder
{
    void buildPartA()
    {
        product.makeA("X-A");
    }

    void buildPartB()
    {
        product.makeB("X-B");
    }

    void buildPartC()
    {
        product.makeC("X-C");
    }
};

class ConcreteBuilderY : public Builder
{
    void buildPartA()
    {
        product.makeA("Y-A");
    }

    void buildPartB()
    {
        product.makeB("Y-B");
    }

    void buildPartC()
    {
        product.makeC("Y-C");
    }
};

class Director
{
public:
    Director() : builder() {}
    ~Director()
    {
        if (builder)
        {
            delete builder;
        }
    }

    void set(Builder *b)
    {
        if (builder)
        {
            delete builder;
        }

        builder = b;
    }

    Product get()
    {
        return builder->get();
    }

    void init()
    {
        builder->buildPartA();
        builder->buildPartB();
        builder->buildPartC();
    }

private:
    Builder *builder;
};

int main()
{
    Director director;

    director.set(new ConcreteBuilderX);
    director.init();
    Product p1 = director.get();
    std::cout << "1st product parts: " << p1.get() << std::endl;

    director.set(new ConcreteBuilderY);
    director.init();
    Product p2 = director.get();
    std::cout << "2st product parts: " << p2.get() << std::endl;

    return 0;
}